{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Natasha"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Natasha solves basic NLP tasks for Russian language: tokenization, sentence segmentatoin, word embedding, morphology tagging, lemmatization, phrase normalization, syntax parsing, NER tagging, fact extraction.\n",
    "\n",
    "Library is just a wrapper for lower level tools from <a href=\"https://github.com/natasha\">Natasha project</a>:\n",
    "\n",
    "* <a href=\"https://github.com/natasha/razdel\">Razdel</a> — token, sentence segmentation for Russian\n",
    "* <a href=\"https://github.com/natasha/navec\">Navec</a> — compact Russian embeddings\n",
    "* <a href=\"https://github.com/natasha/slovnet\">Slovnet</a> — modern deep-learning techniques for Russian NLP, compact models for Russian morphology, syntax, NER.\n",
    "* <a href=\"https://github.com/natasha/yargy\">Yargy</a> — rule-based fact extraction similar to Tomita parser.\n",
    "* <a href=\"https://github.com/natasha/ipymarkup\">Ipymarkup</a> — NLP visualizations for NER and syntax markups.\n",
    "\n",
    "Consider using these lower level tools for realword tasks. Natasha models are optimized for news articles, on other domains quality may be worse."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from natasha import (\n",
    "    Segmenter,\n",
    "    MorphVocab,\n",
    "    \n",
    "    NewsEmbedding,\n",
    "    NewsMorphTagger,\n",
    "    NewsSyntaxParser,\n",
    "    NewsNERTagger,\n",
    "    \n",
    "    PER,\n",
    "    NamesExtractor,\n",
    "    DatesExtractor,\n",
    "    MoneyExtractor,\n",
    "    AddrExtractor,\n",
    "\n",
    "    Doc\n",
    ")\n",
    "\n",
    "segmenter = Segmenter()\n",
    "morph_vocab = MorphVocab()\n",
    "\n",
    "emb = NewsEmbedding()\n",
    "morph_tagger = NewsMorphTagger(emb)\n",
    "syntax_parser = NewsSyntaxParser(emb)\n",
    "ner_tagger = NewsNERTagger(emb)\n",
    "\n",
    "names_extractor = NamesExtractor(morph_vocab)\n",
    "dates_extractor = DatesExtractor(morph_vocab)\n",
    "money_extractor = MoneyExtractor(morph_vocab)\n",
    "addr_extractor = AddrExtractor(morph_vocab)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Getting started"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Doc` aggregates annotators, initially it has just `text` field defined:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Doc(text='Посол Израиля на Украине Йоэль Лион признался, чт...)"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = 'Посол Израиля на Украине Йоэль Лион признался, что пришел в шок, узнав о решении властей Львовской области объявить 2019 год годом лидера запрещенной в России Организации украинских националистов (ОУН) Степана Бандеры. Свое заявление он разместил в Twitter. «Я не могу понять, как прославление тех, кто непосредственно принимал участие в ужасных антисемитских преступлениях, помогает бороться с антисемитизмом и ксенофобией. Украина не должна забывать о преступлениях, совершенных против украинских евреев, и никоим образом не отмечать их через почитание их исполнителей», — написал дипломат. 11 декабря Львовский областной совет принял решение провозгласить 2019 год в регионе годом Степана Бандеры в связи с празднованием 110-летия со дня рождения лидера ОУН (Бандера родился 1 января 1909 года). В июле аналогичное решение принял Житомирский областной совет. В начале месяца с предложением к президенту страны Петру Порошенко вернуть Бандере звание Героя Украины обратились депутаты Верховной Рады. Парламентарии уверены, что признание Бандеры национальным героем поможет в борьбе с подрывной деятельностью против Украины в информационном поле, а также остановит «распространение мифов, созданных российской пропагандой». Степан Бандера (1909-1959) был одним из лидеров Организации украинских националистов, выступающей за создание независимого государства на территориях с украиноязычным населением. В 2010 году в период президентства Виктора Ющенко Бандера был посмертно признан Героем Украины, однако впоследствии это решение было отменено судом. '\n",
    "doc = Doc(text)\n",
    "doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After applying `segmenter` two new fields appear `sents` and `tokens`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Doc(text='Посол Израиля на Украине Йоэль Лион признался, чт..., tokens=[...], sents=[...])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "[DocSent(stop=218, text='Посол Израиля на Украине Йоэль Лион признался, чт..., tokens=[...]),\n",
       " DocSent(start=219, stop=257, text='Свое заявление он разместил в Twitter.', tokens=[...])]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "[DocToken(stop=5, text='Посол'),\n",
       " DocToken(start=6, stop=13, text='Израиля'),\n",
       " DocToken(start=14, stop=16, text='на'),\n",
       " DocToken(start=17, stop=24, text='Украине'),\n",
       " DocToken(start=25, stop=30, text='Йоэль')]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "doc.segment(segmenter)\n",
    "display(doc)\n",
    "display(doc.sents[:2])\n",
    "display(doc.tokens[:5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After applying `morph_tagger` and `syntax_parser`, tokens get 5 new fields `id`, `pos`, `feats`, `head_id`, `rel` — annotation in <a href=\"https://universaldependencies.org/\">Universal Dependencies format</a>:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[DocToken(stop=5, text='Посол', id='1_1', head_id='1_7', rel='nsubj', pos='NOUN', feats=<Anim,Nom,Masc,Sing>),\n",
       " DocToken(start=6, stop=13, text='Израиля', id='1_2', head_id='1_1', rel='nmod', pos='PROPN', feats=<Inan,Gen,Masc,Sing>),\n",
       " DocToken(start=14, stop=16, text='на', id='1_3', head_id='1_4', rel='case', pos='ADP'),\n",
       " DocToken(start=17, stop=24, text='Украине', id='1_4', head_id='1_1', rel='nmod', pos='PROPN', feats=<Inan,Loc,Fem,Sing>),\n",
       " DocToken(start=25, stop=30, text='Йоэль', id='1_5', head_id='1_1', rel='appos', pos='PROPN', feats=<Anim,Nom,Masc,Sing>)]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "doc.tag_morph(morph_tagger)\n",
    "doc.parse_syntax(syntax_parser)\n",
    "display(doc.tokens[:5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After applying `ner_tagger` doc gets `spans` field with PER, LOC, ORG annotation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[DocSpan(start=6, stop=13, type='LOC', text='Израиля', tokens=[...]),\n",
       " DocSpan(start=17, stop=24, type='LOC', text='Украине', tokens=[...]),\n",
       " DocSpan(start=25, stop=35, type='PER', text='Йоэль Лион', tokens=[...]),\n",
       " DocSpan(start=89, stop=106, type='LOC', text='Львовской области', tokens=[...]),\n",
       " DocSpan(start=152, stop=158, type='LOC', text='России', tokens=[...])]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "doc.tag_ner(ner_tagger)\n",
    "display(doc.spans[:5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Visualizations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Natasha wraps <a href=\"https://github.com/natasha/ipymarkup\">Ipymarkup</a> to provide ASCII visualizations for morphology, syntax and NER annotations. `doc` and `sents` have 3 methods: `morph.print()`, `syntax.print()` and `ner.print()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Посол Израиля на Украине Йоэль Лион признался, что пришел в шок, узнав\n",
      "      LOC────    LOC──── PER───────                                   \n",
      " о решении властей Львовской области объявить 2019 год годом лидера \n",
      "                   LOC──────────────                                \n",
      "запрещенной в России Организации украинских националистов (ОУН) \n",
      "              LOC─── ORG─────────────────────────────────────── \n",
      "Степана Бандеры. Свое заявление он разместил в Twitter. «Я не могу \n",
      "PER────────────                                ORG────             \n",
      "понять, как прославление тех, кто непосредственно принимал участие в \n",
      "ужасных антисемитских преступлениях, помогает бороться с \n",
      "антисемитизмом и ксенофобией. Украина не должна забывать о \n",
      "                              LOC────                      \n",
      "преступлениях, совершенных против украинских евреев, и никоим образом \n",
      "не отмечать их через почитание их исполнителей», — написал дипломат. \n",
      "11 декабря Львовский областной совет принял решение провозгласить 2019\n",
      "           ORG──────────────────────                                  \n",
      " год в регионе годом Степана Бандеры в связи с празднованием 110-летия\n",
      "                     PER────────────                                  \n",
      " со дня рождения лидера ОУН (Бандера родился 1 января 1909 года). В \n",
      "                        ORG                                         \n",
      "июле аналогичное решение принял Житомирский областной совет. В начале \n",
      "                                ORG────────────────────────           \n",
      "месяца с предложением к президенту страны Петру Порошенко вернуть \n",
      "                                          PER────────────         \n",
      "Бандере звание Героя Украины обратились депутаты Верховной Рады. \n",
      "PER────              LOC────                     ORG───────────  \n",
      "Парламентарии уверены, что признание Бандеры национальным героем \n",
      "                                     PER────                     \n",
      "поможет в борьбе с подрывной деятельностью против Украины в \n",
      "                                                  LOC────   \n",
      "информационном поле, а также остановит «распространение мифов, \n",
      "созданных российской пропагандой». Степан Бандера (1909-1959) был \n",
      "                                   PER───────────                 \n",
      "одним из лидеров Организации украинских националистов, выступающей за \n",
      "                 ORG─────────────────────────────────                 \n",
      "создание независимого государства на территориях с украиноязычным \n",
      "населением. В 2010 году в период президентства Виктора Ющенко Бандера \n",
      "                                               PER─────────── PER──── \n",
      "был посмертно признан Героем Украины, однако впоследствии это решение \n",
      "                             LOC────                                  \n",
      "было отменено судом. \n"
     ]
    }
   ],
   "source": [
    "doc.ner.print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "               Посол NOUN|Animacy=Anim|Case=Nom|Gender=Masc|Number=Sing\n",
      "             Израиля PROPN|Animacy=Inan|Case=Gen|Gender=Masc|Number=Sing\n",
      "                  на ADP\n",
      "             Украине PROPN|Animacy=Inan|Case=Loc|Gender=Fem|Number=Sing\n",
      "               Йоэль PROPN|Animacy=Anim|Case=Nom|Gender=Masc|Number=Sing\n",
      "                Лион PROPN|Animacy=Anim|Case=Nom|Gender=Masc|Number=Sing\n",
      "           признался VERB|Aspect=Perf|Gender=Masc|Mood=Ind|Number=Sing|Tense=Past|VerbForm=Fin|Voice=Mid\n",
      "                   , PUNCT\n",
      "                 что SCONJ\n",
      "              пришел VERB|Aspect=Perf|Gender=Masc|Mood=Ind|Number=Sing|Tense=Past|VerbForm=Fin|Voice=Act\n",
      "                   в ADP\n",
      "                 шок NOUN|Animacy=Inan|Case=Acc|Gender=Masc|Number=Sing\n",
      "                   , PUNCT\n",
      "               узнав VERB|Aspect=Perf|Tense=Past|VerbForm=Conv|Voice=Act\n",
      "                   о ADP\n",
      "             решении NOUN|Animacy=Inan|Case=Loc|Gender=Neut|Number=Sing\n",
      "             властей NOUN|Animacy=Inan|Case=Gen|Gender=Fem|Number=Plur\n",
      "           Львовской ADJ|Case=Gen|Degree=Pos|Gender=Fem|Number=Sing\n",
      "             области NOUN|Animacy=Inan|Case=Gen|Gender=Fem|Number=Sing\n",
      "            объявить VERB|Aspect=Perf|VerbForm=Inf|Voice=Act\n",
      "                2019 ADJ\n",
      "                 год NOUN|Animacy=Inan|Case=Acc|Gender=Masc|Number=Sing\n",
      "               годом NOUN|Animacy=Inan|Case=Ins|Gender=Masc|Number=Sing\n",
      "              лидера NOUN|Animacy=Anim|Case=Gen|Gender=Masc|Number=Sing\n",
      "         запрещенной VERB|Aspect=Perf|Case=Gen|Gender=Fem|Number=Sing|Tense=Past|VerbForm=Part|Voice=Pass\n",
      "                   в ADP\n",
      "              России PROPN|Animacy=Inan|Case=Loc|Gender=Fem|Number=Sing\n",
      "         Организации PROPN|Animacy=Inan|Case=Gen|Gender=Fem|Number=Sing\n",
      "          украинских ADJ|Case=Gen|Degree=Pos|Number=Plur\n",
      "       националистов NOUN|Animacy=Anim|Case=Gen|Gender=Masc|Number=Plur\n",
      "                   ( PUNCT\n",
      "                 ОУН PROPN|Animacy=Inan|Case=Nom|Gender=Fem|Number=Sing\n",
      "                   ) PUNCT\n",
      "             Степана PROPN|Animacy=Anim|Case=Gen|Gender=Masc|Number=Sing\n",
      "             Бандеры PROPN|Animacy=Anim|Case=Gen|Gender=Masc|Number=Sing\n",
      "                   . PUNCT\n"
     ]
    }
   ],
   "source": [
    "sent = doc.sents[0]\n",
    "sent.morph.print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "        ┌──► Посол         nsubj\n",
      "        │    Израиля       \n",
      "        │ ┌► на            case\n",
      "        │ └─ Украине       \n",
      "        │ ┌─ Йоэль         \n",
      "        │ └► Лион          flat:name\n",
      "┌─────┌─└─── признался     \n",
      "│     │ ┌──► ,             punct\n",
      "│     │ │ ┌► что           mark\n",
      "│     └►└─└─ пришел        ccomp\n",
      "│     │   ┌► в             case\n",
      "│     └──►└─ шок           obl\n",
      "│         ┌► ,             punct\n",
      "│ ┌────►┌─└─ узнав         advcl\n",
      "│ │     │ ┌► о             case\n",
      "│ │ ┌───└►└─ решении       obl\n",
      "│ │ │ ┌─└──► властей       nmod\n",
      "│ │ │ │   ┌► Львовской     amod\n",
      "│ │ │ └──►└─ области       nmod\n",
      "│ └─└►┌─┌─── объявить      nmod\n",
      "│     │ │ ┌► 2019          amod\n",
      "│     │ └►└─ год           obj\n",
      "│     └──►┌─ годом         obl\n",
      "│   ┌─────└► лидера        nmod\n",
      "│   │ ┌►┌─── запрещенной   acl\n",
      "│   │ │ │ ┌► в             case\n",
      "│   │ │ └►└─ России        obl\n",
      "│ ┌─└►└─┌─── Организации   nmod\n",
      "│ │     │ ┌► украинских    amod\n",
      "│ │   ┌─└►└─ националистов nmod\n",
      "│ │   │   ┌► (             punct\n",
      "│ │   └►┌─└─ ОУН           parataxis\n",
      "│ │     └──► )             punct\n",
      "│ └──────►┌─ Степана       appos\n",
      "│         └► Бандеры       flat:name\n",
      "└──────────► .             punct\n"
     ]
    }
   ],
   "source": [
    "sent.syntax.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lemmatization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tokens have `lemmatize` method, it uses `pos` and `feats` assigned by `morph_tagger` to get word normal form. `morph_vocab` is just a wrapper for <a href=\"https://pymorphy2.readthedocs.io/en/latest/\">Pymorphy2</a>:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Посол': 'посол',\n",
       " 'Израиля': 'израиль',\n",
       " 'на': 'на',\n",
       " 'Украине': 'украина',\n",
       " 'Йоэль': 'йоэль',\n",
       " 'Лион': 'лион',\n",
       " 'признался': 'признаться',\n",
       " ',': ',',\n",
       " 'что': 'что',\n",
       " 'пришел': 'прийти'}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "for token in doc.tokens:\n",
    "    token.lemmatize(morph_vocab)\n",
    "    \n",
    "{_.text: _.lemma for _ in doc.tokens[:10]}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Phrase normalization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Consider phrase \"Организации украинских националистов\", one can not just inflect every word independently to get normal form: \"Организация украинский националист\". Spans have method `normalize` that uses syntax annotation by `syntax_parser` to inflect phrases:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Израиля': 'Израиль',\n",
       " 'Украине': 'Украина',\n",
       " 'Йоэль Лион': 'Йоэль Лион',\n",
       " 'Львовской области': 'Львовская область',\n",
       " 'России': 'Россия',\n",
       " 'Организации украинских националистов (ОУН)': 'Организация украинских националистов (ОУН)',\n",
       " 'Степана Бандеры': 'Степан Бандера',\n",
       " 'Twitter': 'Twitter',\n",
       " 'Украина': 'Украина',\n",
       " 'Львовский областной совет': 'Львовский областной совет',\n",
       " 'ОУН': 'ОУН',\n",
       " 'Житомирский областной совет': 'Житомирский областной совет',\n",
       " 'Петру Порошенко': 'Петр Порошенко',\n",
       " 'Бандере': 'Бандера',\n",
       " 'Украины': 'Украина',\n",
       " 'Верховной Рады': 'Верховная Рада',\n",
       " 'Бандеры': 'Бандера',\n",
       " 'Степан Бандера': 'Степан Бандера',\n",
       " 'Организации украинских националистов': 'Организация украинских националистов',\n",
       " 'Виктора Ющенко': 'Виктор Ющенко',\n",
       " 'Бандера': 'Бандера'}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "for span in doc.spans:\n",
    "    span.normalize(morph_vocab)\n",
    "    \n",
    "{_.text: _.normal for _ in doc.spans}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fact extraction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To split names like \"Виктор Ющенко\", \"Бандера\" and \"Йоэль Лион\" into parts use `names_extractor` and spans method `extract_fact`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Йоэль Лион': {'first': 'Йоэль', 'last': 'Лион'},\n",
       " 'Степан Бандера': {'first': 'Степан', 'last': 'Бандера'},\n",
       " 'Петр Порошенко': {'first': 'Петр', 'last': 'Порошенко'},\n",
       " 'Бандера': {'last': 'Бандера'},\n",
       " 'Виктор Ющенко': {'first': 'Виктор', 'last': 'Ющенко'}}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "for span in doc.spans:\n",
    "    if span.type == PER:\n",
    "        span.extract_fact(names_extractor)\n",
    "    \n",
    "{_.normal: _.fact.as_dict for _ in doc.spans if _.fact}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Reference"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One may use Natasha components independently. It is not mandatory to construct `Doc` object."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `Segmenter`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Segmenter` is just a wrapper for <a href=\"https://github.com/natasha/razdel\">Razdel</a>, it has two methods `tokenize` and `sentenize`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Token(start=0, stop=13, text='Кружка-термос')\n",
      "Token(start=14, stop=16, text='на')\n",
      "Token(start=17, stop=20, text='0.5')\n",
      "Token(start=20, stop=21, text='л')\n",
      "Token(start=22, stop=23, text='(')\n"
     ]
    }
   ],
   "source": [
    "tokens = list(segmenter.tokenize('Кружка-термос на 0.5л (50/64 см³, 516;...)'))\n",
    "for token in tokens[:5]:\n",
    "    print(token)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sent(start=1, stop=23, text='- \"Так в чем же дело?\"')\n",
      "Sent(start=24, stop=40, text='- \"Не ра-ду-ют\".')\n",
      "Sent(start=42, stop=57, text='И т. д. и т. п.')\n",
      "Sent(start=58, stop=77, text='В общем, вся газета')\n"
     ]
    }
   ],
   "source": [
    "text = '''\n",
    "- \"Так в чем же дело?\" - \"Не ра-ду-ют\".\n",
    " И т. д. и т. п. В общем, вся газета\n",
    "'''\n",
    "sents = list(segmenter.sentenize(text))\n",
    "for sent in sents:\n",
    "    print(sent)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `MorphVocab`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`MorphVocab` is a wrapper for <a href=\"pymorphy2.readthedocs.io/en/latest/\">Pymorphy2</a>. `MorphVocab` adds cache and adapts grammems to Universal Dependencies format:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[MorphForm(normal='стать', pos='VERB', feats={'VerbForm': 'Fin', 'Aspect': 'Perf', 'Number': 'Plur', 'Tense': 'Past', 'Mood': 'Ind'}),\n",
       " MorphForm(normal='сталь', pos='NOUN', feats={'Animacy': 'Inan', 'Gender': 'Fem', 'Number': 'Sing', 'Case': 'Gen'}),\n",
       " MorphForm(normal='сталь', pos='NOUN', feats={'Animacy': 'Inan', 'Gender': 'Fem', 'Number': 'Plur', 'Case': 'Nom'}),\n",
       " MorphForm(normal='сталь', pos='NOUN', feats={'Animacy': 'Inan', 'Gender': 'Fem', 'Number': 'Sing', 'Case': 'Dat'}),\n",
       " MorphForm(normal='сталь', pos='NOUN', feats={'Animacy': 'Inan', 'Gender': 'Fem', 'Number': 'Sing', 'Case': 'Loc'}),\n",
       " MorphForm(normal='сталь', pos='NOUN', feats={'Animacy': 'Inan', 'Gender': 'Fem', 'Number': 'Plur', 'Case': 'Acc'})]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "forms = morph_vocab('стали')\n",
    "forms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "CacheInfo(hits=214, misses=635, maxsize=10000, currsize=635)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "morph_vocab.__call__.cache_info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Also `MorphVocab` adds method `lemmatize`. Given `pos` and `feats` it selects the most suitable morph form and returns its `normal` field:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'стать'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "morph_vocab.lemmatize('стали', 'VERB', {})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'сталь'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "morph_vocab.lemmatize('стали', 'X', {'Case': 'Gen'})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `Embedding`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Embedding` is a wrapper for <a href=\"https://github.com/natasha/navec/\">Navec</a> — compact pretrained word embeddings for Russian language:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Words in vocab + 2 for pad and unk: 250002\n"
     ]
    }
   ],
   "source": [
    "print('Words in vocab + 2 for pad and unk: %d' % len(emb.vocab.words) )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.3309305 ,  0.18249014,  0.23347412,  0.14935994, -0.17402406,\n",
       "       -0.47864223, -0.24524143,  0.15673256, -0.08669729, -0.11727095],\n",
       "      dtype=float32)"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "emb['навек'][:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `MorphTagger`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`MorphTagger` wraps <a href=\"https://github.com/natasha/slovnet\">Slovnet morphology tagger</a>. Tagger has list of words as input and returns markup object. Markup has `print` method that outputs morph tags ASCII visualization:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "         Европейский ADJ|Case=Nom|Degree=Pos|Gender=Masc|Number=Sing\n",
      "                союз NOUN|Animacy=Inan|Case=Nom|Gender=Masc|Number=Sing\n",
      "             добавил VERB|Aspect=Perf|Gender=Masc|Mood=Ind|Number=Sing|Tense=Past|VerbForm=Fin|Voice=Act\n",
      "                   в ADP\n",
      "         санкционный ADJ|Animacy=Inan|Case=Acc|Degree=Pos|Gender=Masc|Number=Sing\n",
      "              список NOUN|Animacy=Inan|Case=Acc|Gender=Masc|Number=Sing\n",
      "              девять NUM|Case=Nom\n",
      "        политических ADJ|Case=Gen|Degree=Pos|Number=Plur\n",
      "            деятелей NOUN|Animacy=Anim|Case=Gen|Gender=Masc|Number=Plur\n"
     ]
    }
   ],
   "source": [
    "words = ['Европейский', 'союз', 'добавил', 'в', 'санкционный', 'список', 'девять', 'политических', 'деятелей']\n",
    "markup = morph_tagger(words)\n",
    "markup.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `SyntaxParser`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`SyntaxParser` wraps <a href=\"https://github.com/natasha/slovnet\">Slovnet syntax parser</a>. Interface is similar to `MorphTagger`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "      ┌► Европейский  amod\n",
      "    ┌►└─ союз         nsubj\n",
      "  ┌─└─── добавил      \n",
      "  │ ┌──► в            case\n",
      "  │ │ ┌► санкционный  amod\n",
      "┌─└►└─└─ список       obl\n",
      "│   ┌──► девять       nummod:gov\n",
      "│   │ ┌► политических amod\n",
      "└──►└─└─ деятелей     nmod\n"
     ]
    }
   ],
   "source": [
    "words = ['Европейский', 'союз', 'добавил', 'в', 'санкционный', 'список', 'девять', 'политических', 'деятелей']\n",
    "markup = syntax_parser(words)\n",
    "markup.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `NERTagger`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`NERTagger` wraps <a href=\"https://github.com/natasha/slovnet\">Slovnet NER tagger</a>. Interface is similar to `MorphTagger` but has untokenized text as input:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Посол Израиля на Украине Йоэль Лион признался, что пришел в шок, узнав\n",
      "      LOC────    LOC──── PER───────                                   \n",
      " о решении властей Львовской области объявить 2019 год годом лидера \n",
      "                   LOC──────────────                                \n",
      "запрещенной в России Организации украинских националистов (ОУН) \n",
      "              LOC─── ORG─────────────────────────────────────── \n",
      "Степана Бандеры. Свое заявление он разместил в Twitter. 11 декабря \n",
      "PER────────────                                ORG────             \n",
      "Львовский областной совет принял решение провозгласить 2019 год в \n",
      "ORG──────────────────────                                         \n",
      "регионе годом Степана Бандеры в связи с празднованием 110-летия со дня\n",
      "              PER────────────                                         \n",
      " рождения лидера ОУН (Бандера родился 1 января 1909 года).\n",
      "                 ORG                                      \n"
     ]
    }
   ],
   "source": [
    "text = 'Посол Израиля на Украине Йоэль Лион признался, что пришел в шок, узнав о решении властей Львовской области объявить 2019 год годом лидера запрещенной в России Организации украинских националистов (ОУН) Степана Бандеры. Свое заявление он разместил в Twitter. 11 декабря Львовский областной совет принял решение провозгласить 2019 год в регионе годом Степана Бандеры в связи с празднованием 110-летия со дня рождения лидера ОУН (Бандера родился 1 января 1909 года).'\n",
    "markup = ner_tagger(text)\n",
    "markup.print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `Extractor`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition to `names_extractor` Natasha bundles several other extractors: `dates_extractor`, `money_extractor` and `addr_extractor`. All extractors are based on <a href=\"https://github.com/natasha/yargy\">Yargy-parser</a>, meaning that they work correctly only on small predefined set of texts. For realword tasks consider writing your own grammar, see <a href=\"https://github.com/natasha/yargy#documentation\">Yargy docs</a> for more."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `DatesExtractor`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Match(\n",
       "     start=0,\n",
       "     stop=10,\n",
       "     fact=Date(\n",
       "         year=2017,\n",
       "         month=1,\n",
       "         day=24\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=12,\n",
       "     stop=20,\n",
       "     fact=Date(\n",
       "         year=2015,\n",
       "         month=None,\n",
       "         day=None\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=22,\n",
       "     stop=28,\n",
       "     fact=Date(\n",
       "         year=2014,\n",
       "         month=None,\n",
       "         day=None\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=30,\n",
       "     stop=38,\n",
       "     fact=Date(\n",
       "         year=None,\n",
       "         month=4,\n",
       "         day=1\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=40,\n",
       "     stop=51,\n",
       "     fact=Date(\n",
       "         year=2017,\n",
       "         month=5,\n",
       "         day=None\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=53,\n",
       "     stop=68,\n",
       "     fact=Date(\n",
       "         year=2017,\n",
       "         month=5,\n",
       "         day=9\n",
       "     )\n",
       " )]"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = '24.01.2017, 2015 год, 2014 г, 1 апреля, май 2017 г., 9 мая 2017 года'\n",
    "list(dates_extractor(text))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `MoneyExtractor`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Match(\n",
       "     start=0,\n",
       "     stop=18,\n",
       "     fact=Money(\n",
       "         amount=1599059.38,\n",
       "         currency='EUR'\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=20,\n",
       "     stop=32,\n",
       "     fact=Money(\n",
       "         amount=420,\n",
       "         currency='USD'\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=34,\n",
       "     stop=44,\n",
       "     fact=Money(\n",
       "         amount=20000000,\n",
       "         currency='RUB'\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=46,\n",
       "     stop=54,\n",
       "     fact=Money(\n",
       "         amount=20000,\n",
       "         currency='RUB'\n",
       "     )\n",
       " ),\n",
       " Match(\n",
       "     start=56,\n",
       "     stop=133,\n",
       "     fact=Money(\n",
       "         amount=881913.98,\n",
       "         currency='RUB'\n",
       "     )\n",
       " )]"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = '1 599 059, 38 Евро, 420 долларов, 20 млн руб, 20 т. р., 881 913 (Восемьсот восемьдесят одна тысяча девятьсот тринадцать) руб. 98 коп.'\n",
    "list(money_extractor(text))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `NamesExtractor`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`names_extractor` should be applied only to spans of text. To extract single fact use method `find`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Match(\n",
       "    start=0,\n",
       "    stop=16,\n",
       "    fact=Name(\n",
       "        first='Мустафа',\n",
       "        last='Джемилев',\n",
       "        middle=None\n",
       "    )\n",
       ")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Match(\n",
       "    start=0,\n",
       "    stop=1,\n",
       "    fact=Name(\n",
       "        first=None,\n",
       "        last='О',\n",
       "        middle=None\n",
       "    )\n",
       ")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Match(\n",
       "    start=0,\n",
       "    stop=22,\n",
       "    fact=Name(\n",
       "        first='Фёдор',\n",
       "        last='Шаляпин',\n",
       "        middle='Иванович'\n",
       "    )\n",
       ")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Match(\n",
       "    start=0,\n",
       "    stop=8,\n",
       "    fact=Name(\n",
       "        first=None,\n",
       "        last='Янукович',\n",
       "        middle=None\n",
       "    )\n",
       ")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "lines = [\n",
    "    'Мустафа Джемилев',\n",
    "    'О. Дерипаска',\n",
    "    'Фёдор Иванович Шаляпин',\n",
    "    'Янукович'\n",
    "]\n",
    "for line in lines:\n",
    "    display(names_extractor.find(line))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `AddrExtractor`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Match(\n",
       "    start=0,\n",
       "    stop=48,\n",
       "    fact=Addr(\n",
       "        parts=[AddrPart(\n",
       "             value='Россия',\n",
       "             type='страна'\n",
       "         ),\n",
       "         AddrPart(\n",
       "             value='Вологодская',\n",
       "             type='область'\n",
       "         ),\n",
       "         AddrPart(\n",
       "             value='Череповец',\n",
       "             type='город'\n",
       "         ),\n",
       "         AddrPart(\n",
       "             value='Победы',\n",
       "             type='проспект'\n",
       "         )]\n",
       "    )\n",
       ")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Match(\n",
       "    start=0,\n",
       "    stop=56,\n",
       "    fact=Addr(\n",
       "        parts=[AddrPart(\n",
       "             value='692909',\n",
       "             type='индекс'\n",
       "         ),\n",
       "         AddrPart(\n",
       "             value='РФ',\n",
       "             type='страна'\n",
       "         ),\n",
       "         AddrPart(\n",
       "             value='Приморский',\n",
       "             type='край'\n",
       "         ),\n",
       "         AddrPart(\n",
       "             value='Находка',\n",
       "             type='город'\n",
       "         ),\n",
       "         AddrPart(\n",
       "             value='Добролюбова',\n",
       "             type='улица'\n",
       "         )]\n",
       "    )\n",
       ")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Match(\n",
       "    start=0,\n",
       "    stop=29,\n",
       "    fact=Addr(\n",
       "        parts=[AddrPart(\n",
       "             value='Народного Ополчения',\n",
       "             type='улица'\n",
       "         ),\n",
       "         AddrPart(\n",
       "             value='9к',\n",
       "             type='дом'\n",
       "         )]\n",
       "    )\n",
       ")"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "lines = [\n",
    "    'Россия, Вологодская обл. г. Череповец, пр.Победы 93 б',\n",
    "    '692909, РФ, Приморский край, г. Находка, ул. Добролюбова, 18',\n",
    "    'ул. Народного Ополчения д. 9к.3'\n",
    "]\n",
    "for line in lines:\n",
    "    display(addr_extractor.find(line))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
